将 Mastodon 迁移回家

本文篇幅有点长,其内容主要是围绕个人部署与迁移 Mastodon 实例时遇到的问题,并一一给出自己相应的解决方法。文章内容可能描述得不够清楚或者有错误,仅供参考。

折腾 Mastodon 有一段时间了,开始我只想体验一下,但一段时间后觉得这个平台非常好用,加上 Memos 的更新越来越让我不懂了,于是决定弃用本地部署的 Memos,全面使用 Mastodon。

既然决定长期使用,我就开始想办法将它从测试服务器上迁移回本地的服务器,毕竟服务器的性能相对高一些,数据的备份在本地上也灵活很多。可当开始着手时才发现部署 Mastodon 要注意的细节太多了,自己这两天可踩了不少的坑。

源码部署

当初为了体验,使用 Docker 部署后又改用源码重新部署了一遍。得益于官方文档1的详细,我们可以很简单的构建起自己的实例。

接下来简单记录一下折腾期间碰到的几个问题。

问题一、Nginx 缓存

Mastodon 提供了非常棒的 Nginx 模板2,简单的修改就可以成功在服务器上完成配置,一般只需修改 server_name 与解除注释证书那两行即可。

但我测试期间发现即使我更新了 Nginx 或 Mastodon 的配置,页面不会有任何的变化,仔细查看官方提供的 Nginx 模板发现了这一行。

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;

解决办法:

rm -rf /var/cache/nginx/*

CleanShot-2024-03-24-at-15.54.37@2x

一开始我根据文档上的要求使用了 Ubuntu 20.04,部署非常顺利,没有出现页面只显示 Logo 这个问题,但当迁移至的服务器版本为 Ubuntu 22.04 时就出现了。

解决办法3

sudo su -
usermod -aG mastodon www-data
nginx -s reload

也可以参考这个 Issues4

问题三、迁移后重构时间流时数据库无法连接

RAILS_ENV=production ./bin/tootctl feeds build

CleanShot-2024-03-24-at-09.53.06@2x

此问题困扰我最久,自己第一次接触 PostgreSQL,遇到问题往复杂方向去思考,反而忽略了细节问题,有时间还是需要基础地学习一下 PostgreSQL。

解决办法:

返回 root

sudo -u postgres psql
# passwd 修改成 .env.production 上的数据库密码
ALTER USER postgres WITH PASSWORD 'passwd';
\q

注:

我的数据库用户为 postgres 是因为我的实例最开始是使用 Docker 来部署的,当时我没搞明白这个 DB_USER,所以就使用默认的。经过一次次尝试,又一次次失败,我总算悟了一点点。新建实例配置时要使用自定义的数据库用户名,就得先在 PostgreSQL 上新建一个对应的用户(下文有举例),用 Docker Compose 部署也一样,需先在 db 这个容器上新建对应的用户。

Docker Compose 部署

# 创建目录
mkdir -p ~/docker/mastodon

# 进入目录
cd ~/docker/mastodon

# 下载官方模板
wget https://raw.githubusercontent.com/mastodon/mastodon/main/.env.production.sample -O .env.production
wget https://raw.githubusercontent.com/mastodon/mastodon/main/docker-compose.yml

# 编辑
vim docker-compose.yml

简单说明:

  • 不使用构建,因此将 web、streaming、sidekiq 这三个服务上的 build: . 进行注释;
  • 修改镜像版本,如 image: ghcr.io/mastodon/mastodon:v4.2.8 或者直接使用 latest
  • 如若服务器配置还行的话,可以开启搜索功能,将 es 服务上的注释删除即可;
  • 如若通过远程服务器反向代理本地容器,将 web、streaming 上的端口映射前的 127.0.0.1: 删除;

配置过程需注意:

  • .env.production 上对应的服务 HOST 可使用 docker ps 查看,对应其 NAMES 上的值。如若没有进行自定义,则为 docker-compose.yml 所在目录名称-服务名称-1
  • 当实例配置完成后记得手动将复制到 .env.production 里;

举例说明:

一、进行实例配置时要使用自定义的数据库用户名,需要先创建用户(上文有所提及);

CleanShot-2024-03-24-at-14.01.01@2x

exit 退出 db 容器内部就可以开始配置实例了。

CleanShot-2024-03-24-at-14.04.21@2x

二、开启 es 搜索服务遇到的问题;

预先创建目录

如若让 Docker Compose 运行时再自动创建,会报权限错误。

mkdir elasticsearch
chown -R 1000:1000 elasticsearch

具体原因我们进入 mastodon-es-1 这个容器内部查看后应该可以联想得到。

CleanShot-2024-03-24-at-18.13.03@2x

虚拟内存区域

ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch. bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] ERROR: Elasticsearch did not exit normally - check the logs at /usr/share/elasticsearch/logs/es-mastodon.log

提示最大虚拟内存区域 vm.max_map_count 的值过低,需要至少增加到 262144

vim /etc/sysctl.conf

# 文件末尾添加
vm.max_map_count=262144

# 让修改生效
sysctl -p

# 启动项目
docker compose up -d

# 部署搜索功能
docker compose run --rm web bin/tootctl search deploy

三、Nginx 配置;

篇幅关系,只帖出Nginx修改的部分,注意末尾处省略的修改,其他省略部分均与源码部署一致。

...

upstream backend {
  # 有公网IP直接使用DDNS与端口映射,否则需内网穿透。(若部署在云服务器上,此处保留为:127.0.0.1)
    server nas.280562.com:3000 fail_timeout=0;
}

upstream streaming {
    least_conn;
	# 有公网IP直接使用DDNS与端口映射,否则需内网穿透。(若部署在云服务器上,此处保留为:127.0.0.1)
    server nas.280562.com:4000 fail_timeout=0;
}

...

  # If Docker is used for deployment and Rails serves static files,
  # then needed must replace line `try_files $uri =404;` with `try_files $uri @proxy;`.
  location = /sw.js {
    add_header Cache-Control "public, max-age=604800, must-revalidate";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
  # 模板上注释里有提及,如果使用Docker来部署,则需要修改此处,下面省略的所有 $uri =404; 都需要统一改成 $uri @proxy;
    try_files $uri @proxy;
  }

...

四、从源码部署迁移回本地的 Docker Compose 部署;

要注意的点基本上前文已有所提及,接下来只记录自己迁移过程的实操。

# 假设已经完成简单说明前的步骤

# 在旧服务器上导出数据库
su - mastodon
pg_dump -Fc mastodon_production -f backup.dump
exit

# 将数据库文件传输回本地
rsync -av root@远程服务IP:/home/mastodon/backup.dump ~/docker/mastodon/backup.dump

# 在新服务器上启动 db 服务
cd ~/docker/mastodon
docker compose up -d db

# 将数据库文件复制到 mastodon-db-1 的容器内部
docker cp ./backup.dump mastodon-db-1:/tmp/backup.dump

# 进入 mastodon-db-1 容器内部
docker exec -it mastodon-db-1 /bin/bash

# 因为我的 DB_USER 用户使用了默认的 postgres,故迁移时可直接创建数据库
su - postgres
createdb -T template0 mastodon_production
# 导入数据库文件
pg_restore -U postgres -n public --no-owner --role=postgres -d mastodon_production /tmp/backup.dump

# 若数据库用户为其他,则按以下步骤给用户赋予数据库相应的权限
# 用户以 mastodon 为例
psql -U postgres
CREATE USER mastodon WITH PASSWORD 'passwd';
GRANT ALL PRIVILEGES ON DATABASE mastodon_production TO mastodon;
\q

# 返回到宿主机
exit
exit

# 将媒体文件传输回本地
rsync -av root@远程服务IP:/home/mastodon/live/public/system ~/docker/mastodon/public/
# 修改目录权限,与前文提到的 es 搜索服务理由一致
chown 991:991 -R public

# 重构时间流
docker compose run --rm web bin/tootctl feeds build

# 如果实例开启了搜索功能,此时可进行搜索部署,具体方法前方有所提及。

# 反向代理,在远程服务器上设置 Nginx 配置,因在本地部署,故其中涉及的内容过多,或有机会再展开细说。

结语

这两年自己已经成功投入到 Docker 容器化的大怀抱里,一般能使用 Docker 部署的项目我都会使用 Docker。Mastodon 之所以让我使用源码来部署一次,主要是自己想借此机会折腾一番。

现在实例已经完全迁移回本地服务器,期间误操作删除了一些外站的媒体文件,影响不大。最主要是实例也从源码部署转成使用 Docker Compose 来部署,从此不会再有数据库导出导入等麻烦事儿啦,只要使用群晖的 Active Backup for Business 套件将 ~/docker/mastodon 这个目录进行每天备份即可。

Footnotes

  1. https://docs.joinmastodon.org/admin/install/

  2. https://github.com/mastodon/mastodon/blob/main/dist/nginx.conf

  3. https://www.reddit.com/r/Mastodon/comments/zuzt3q/comment/jngrqd8/?utm_source=share&utm_medium=web2x&context=3

  4. https://github.com/mastodon/mastodon/issues/25487